#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Web服务器模块
提供Web界面展示分析结果和API接口
"""

import os
import json
import yaml
import logging
from pathlib import Path
from datetime import datetime, timedelta
from flask import Flask, render_template, jsonify, request, send_from_directory

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

class WebServer:
    """Web服务器类，提供Web界面和API接口"""
    
    def __init__(self, config_path='config/config.yaml'):
        """
        初始化Web服务器
        
        Args:
            config_path: 配置文件路径
        """
        self.config_path = config_path
        self.config = self._load_config()
        self.web_config = self.config.get('web', {})
        
        # 创建Flask应用
        self.app = Flask(__name__, 
                         template_folder=os.path.join(os.path.dirname(__file__), 'templates'),
                         static_folder=os.path.join(os.path.dirname(__file__), 'static'))
        
        # 设置密钥
        self.app.secret_key = self.web_config.get('secret_key', 'stock_news_analysis_system')
        
        # 注册路由
        self._register_routes()
        
        logger.info("Web服务器初始化完成")
    
    def _load_config(self):
        """
        加载配置文件
        
        Returns:
            dict: 配置信息
        """
        try:
            with open(self.config_path, 'r', encoding='utf-8') as f:
                config = yaml.safe_load(f)
            logger.info(f"成功加载配置文件: {self.config_path}")
            return config
        except Exception as e:
            logger.error(f"加载配置文件失败: {e}")
            return {}
    
    def _register_routes(self):
        """注册路由"""
        
        @self.app.route('/')
        def index():
            """首页"""
            return render_template('index.html', title='股票新闻分析系统')
        
        @self.app.route('/dashboard')
        def dashboard():
            """仪表盘页面"""
            return render_template('dashboard.html', title='分析仪表盘')
        
        @self.app.route('/reports')
        def reports():
            """报告列表页面"""
            reports_data = self._get_reports_list()
            return render_template('reports.html', title='策略报告列表', reports=reports_data)
        
        @self.app.route('/report/<date>')
        def report_detail(date):
            """报告详情页面"""
            report_data = self._get_report_data(date)
            if report_data:
                return render_template('report_detail.html', title=f'策略报告 {date}', report=report_data)
            else:
                return render_template('error.html', title='报告不存在', message=f'找不到日期为 {date} 的报告')
        
        @self.app.route('/llm_analysis')
        def llm_analysis():
            """大模型分析页面"""
            llm_data = self._get_llm_analysis_data()
            return render_template('llm_analysis.html', title='大模型分析', llm_data=llm_data)
        
        @self.app.route('/api/llm_analysis')
        def api_llm_analysis():
            """大模型分析API"""
            llm_data = self._get_llm_analysis_data()
            if llm_data:
                return jsonify(llm_data)
            else:
                return jsonify({'error': '找不到大模型分析数据'}), 404
        
        @self.app.route('/api/reports')
        def api_reports():
            """报告列表API"""
            days = request.args.get('days', 7, type=int)
            reports_data = self._get_reports_list(days)
            return jsonify(reports_data)
        
        @self.app.route('/api/report/<date>')
        def api_report_detail(date):
            """报告详情API"""
            report_data = self._get_report_data(date)
            if report_data:
                return jsonify(report_data)
            else:
                return jsonify({'error': f'找不到日期为 {date} 的报告'}), 404
        
        @self.app.route('/api/stocks')
        def api_stocks():
            """股票列表API"""
            stocks_data = self._get_stocks_data()
            return jsonify(stocks_data)
        
        @self.app.route('/api/stock/<stock_code>')
        def api_stock_detail(stock_code):
            """股票详情API"""
            days = request.args.get('days', 30, type=int)
            stock_data = self._get_stock_detail(stock_code, days)
            if stock_data:
                return jsonify(stock_data)
            else:
                return jsonify({'error': f'找不到股票代码为 {stock_code} 的数据'}), 404
        
        @self.app.route('/api/news')
        def api_news():
            """新闻列表API"""
            days = request.args.get('days', 3, type=int)
            news_data = self._get_news_data(days)
            return jsonify(news_data)
    
    def _get_reports_list(self, days=7):
        """
        获取报告列表
        
        Args:
            days: 获取最近几天的报告，默认7天
            
        Returns:
            list: 报告列表
        """
        try:
            results_path = self.config['system']['data_storage']['results_path']
            reports = []
            
            # 获取最近days天的日期
            for i in range(days):
                date = (datetime.now() - timedelta(days=i)).strftime('%Y%m%d')
                report_file = os.path.join(results_path, f'strategy_report_{date}.json')
                
                if os.path.exists(report_file):
                    with open(report_file, 'r', encoding='utf-8') as f:
                        report_data = json.load(f)
                    
                    # 提取摘要信息
                    summary = {
                        'date': date,
                        'title': report_data.get('title', f'策略报告 {date}'),
                        'market_overview': report_data.get('market_overview', '无市场概览'),
                        'recommendation_count': len(report_data.get('recommendations', [])),
                        'risk_level': report_data.get('risk_level', '中等')
                    }
                    
                    reports.append(summary)
            
            return reports
            
        except Exception as e:
            logger.error(f"获取报告列表失败: {e}")
            return []
    
    def _get_report_data(self, date):
        """
        获取报告详情
        
        Args:
            date: 报告日期，格式YYYYMMDD
            
        Returns:
            dict: 报告数据
        """
        try:
            results_path = self.config['system']['data_storage']['results_path']
            report_file = os.path.join(results_path, f'strategy_report_{date}.json')
            
            if os.path.exists(report_file):
                with open(report_file, 'r', encoding='utf-8') as f:
                    report_data = json.load(f)
                return report_data
            else:
                logger.warning(f"报告文件不存在: {report_file}")
                return None
                
        except Exception as e:
            logger.error(f"获取报告详情失败: {e}")
            return None
    
    def _get_stocks_data(self):
        """
        获取股票列表数据
        
        Returns:
            list: 股票列表
        """
        try:
            # 从最新的分析结果中提取股票列表
            results_path = self.config['system']['data_storage']['results_path']
            date = datetime.now().strftime('%Y%m%d')
            
            # 尝试获取今天的数据，如果没有则获取昨天的
            analysis_file = os.path.join(results_path, f'analysis_results_{date}.json')
            if not os.path.exists(analysis_file):
                date = (datetime.now() - timedelta(days=1)).strftime('%Y%m%d')
                analysis_file = os.path.join(results_path, f'analysis_results_{date}.json')
            
            if os.path.exists(analysis_file):
                with open(analysis_file, 'r', encoding='utf-8') as f:
                    analysis_data = json.load(f)
                
                stocks = []
                for stock_code, stock_data in analysis_data.items():
                    stock = {
                        'code': stock_code,
                        'name': stock_data.get('name', '未知'),
                        'industry': stock_data.get('industry', '未知'),
                        'prediction': stock_data.get('prediction', '未知'),
                        'confidence': stock_data.get('confidence', 0),
                        'sentiment': stock_data.get('sentiment_score', 0)
                    }
                    stocks.append(stock)
                
                return stocks
            else:
                logger.warning(f"分析结果文件不存在: {analysis_file}")
                return []
                
        except Exception as e:
            logger.error(f"获取股票列表失败: {e}")
            return []
    
    def _get_stock_detail(self, stock_code, days=30):
        """
        获取股票详情数据
        
        Args:
            stock_code: 股票代码
            days: 获取最近几天的数据，默认30天
            
        Returns:
            dict: 股票详情数据
        """
        try:
            # 获取股票历史分析结果
            results_path = self.config['system']['data_storage']['results_path']
            history = []
            
            # 获取最近days天的数据
            for i in range(days):
                date = (datetime.now() - timedelta(days=i)).strftime('%Y%m%d')
                analysis_file = os.path.join(results_path, f'analysis_results_{date}.json')
                
                if os.path.exists(analysis_file):
                    with open(analysis_file, 'r', encoding='utf-8') as f:
                        analysis_data = json.load(f)
                    
                    if stock_code in analysis_data:
                        stock_data = analysis_data[stock_code]
                        daily_data = {
                            'date': date,
                            'prediction': stock_data.get('prediction', '未知'),
                            'confidence': stock_data.get('confidence', 0),
                            'sentiment': stock_data.get('sentiment_score', 0),
                            'news_count': len(stock_data.get('related_news', []))
                        }
                        history.append(daily_data)
            
            # 获取最新的股票信息
            latest_data = history[0] if history else None
            
            # 如果没有找到任何数据，返回None
            if not latest_data:
                return None
            
            # 构建股票详情
            stock_detail = {
                'code': stock_code,
                'name': '未知',  # 实际中应该从股票基本信息数据库中获取
                'industry': '未知',  # 实际中应该从股票基本信息数据库中获取
                'latest': latest_data,
                'history': history
            }
            
            # 尝试从最新的分析结果中获取股票名称和行业
            if history:
                latest_date = history[0]['date']
                analysis_file = os.path.join(results_path, f'analysis_results_{latest_date}.json')
                
                if os.path.exists(analysis_file):
                    with open(analysis_file, 'r', encoding='utf-8') as f:
                        analysis_data = json.load(f)
                    
                    if stock_code in analysis_data:
                        stock_data = analysis_data[stock_code]
                        stock_detail['name'] = stock_data.get('name', '未知')
                        stock_detail['industry'] = stock_data.get('industry', '未知')
            
            return stock_detail
                
        except Exception as e:
            logger.error(f"获取股票详情失败: {e}")
            return None
    
    def _get_news_data(self, days=3):
        """
        获取新闻数据
        
        Args:
            days: 获取最近几天的新闻，默认3天
            
        Returns:
            list: 新闻列表
        """
        try:
            news_path = self.config['system']['data_storage']['news_data_path']
            news_list = []
            
            # 获取最近days天的新闻
            for i in range(days):
                date = (datetime.now() - timedelta(days=i)).strftime('%Y%m%d')
                news_file = os.path.join(news_path, f'news_{date}.json')
                
                if os.path.exists(news_file):
                    with open(news_file, 'r', encoding='utf-8') as f:
                        daily_news = json.load(f)
                    
                    for news in daily_news:
                        news_list.append({
                            'id': news.get('id', ''),
                            'title': news.get('title', ''),
                            'content': news.get('content', '')[:100] + '...',
                            'source': news.get('source', ''),
                            'date': news.get('date', date),
                            'url': news.get('url', ''),
                            'related_stocks': news.get('related_stocks', [])
                        })
            
            return news_list
                
        except Exception as e:
            logger.error(f"获取新闻数据失败: {e}")
            return []
    
    def _get_llm_analysis_data(self):
        """
        获取LLM分析数据
        
        Returns:
            dict: LLM分析数据
        """
        try:
            # 检查配置中是否启用了LLM分析
            llm_config = self.config.get('llm_analysis', {})
            if not llm_config.get('enabled', False):
                logger.warning("LLM分析未启用")
                return None
                
            # 获取LLM分析结果路径
            llm_output_path = llm_config.get('output_path', 'data/results/llm_analysis/')
            date = datetime.now().strftime('%Y%m%d')
            
            # 尝试获取今天的数据，如果没有则获取昨天的
            llm_file = os.path.join(llm_output_path, f'llm_analysis_{date}.json')
            if not os.path.exists(llm_file):
                date = (datetime.now() - timedelta(days=1)).strftime('%Y%m%d')
                llm_file = os.path.join(llm_output_path, f'llm_analysis_{date}.json')
            
            if os.path.exists(llm_file):
                with open(llm_file, 'r', encoding='utf-8') as f:
                    llm_data = json.load(f)
                
                # 添加时间戳
                llm_data['timestamp'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
                return llm_data
            else:
                logger.warning(f"LLM分析结果文件不存在: {llm_file}")
                
                # 如果没有找到特定日期的文件，尝试查找最新的文件
                try:
                    all_files = [f for f in os.listdir(llm_output_path) if f.startswith('llm_analysis_') and f.endswith('.json')]
                    if all_files:
                        # 按文件名排序，获取最新的文件
                        all_files.sort(reverse=True)
                        latest_file = os.path.join(llm_output_path, all_files[0])
                        
                        with open(latest_file, 'r', encoding='utf-8') as f:
                            llm_data = json.load(f)
                        
                        # 添加时间戳
                        llm_data['timestamp'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
                        logger.info(f"找到最新LLM分析结果文件: {latest_file}")
                        return llm_data
                except Exception as e:
                    logger.error(f"查找最新LLM分析结果文件失败: {e}")
                
                return None
                
        except Exception as e:
            logger.error(f"获取LLM分析数据失败: {e}")
            return None
    
    def run(self, host='0.0.0.0', port=5000, debug=False):
        """
        运行Web服务器
        
        Args:
            host: 主机地址，默认0.0.0.0（所有网络接口）
            port: 端口号，默认5000
            debug: 是否开启调试模式，默认False
        """
        try:
            # 获取配置中的端口
            configured_port = self.web_config.get('port', port)
            configured_host = self.web_config.get('host', host)
            configured_debug = self.web_config.get('debug', debug)
            
            logger.info(f"Web服务器准备启动，监听地址: {configured_host}:{configured_port}")
            self.app.run(host=configured_host, port=configured_port, debug=configured_debug)
            
        except Exception as e:
            logger.error(f"启动Web服务器失败: {e}") 